--[[

    Copyright (c) 2011-2020 baby-bus.com

    TODO:   SpriteName
    Author: DemonYao
    Date:   2020.09.21
 
    http://www.babybus.com/ 

]] 




--------------------------
-- 引入命名空间
--------------------------
-- local BaseLayer = import("app.common.layer.BaseLaye



--[[
    类
--]]


local M = classSprite("dragonBone")
local dbFactory = dragonBones.CCFactory



--------------------------
-- 构造函数
--------------------------

function M:ctor(params)
    -- [超类调用]
    M.super.ctor(self, params)
    -- [本类调用]
    self.dragonBonesDataFile = params.dragonBonesDataFile          -- 骨骼文件
    self.dragonBonesTexFile  = params.dragonBonesTexFile           -- 骨骼文件
    self.dragonBoneDataName  = params.dragonBoneDataName or ""     -- 为骨骼文件数据实例指定一个名词
    self.armatureName        = params.armatureName                 -- 骨骼名称
    self.dragonBonesName     = params.dragonBonesName or ""        -- DragonBonesData 实例的缓存名称。 （如果未设置，将检索所有的 DragonBonesData 实例，当多个 DragonBonesData 实例中包含同名的骨架数据时，可能无法准确的创建出特定的骨架）
    self.skinName            = params.params or ""                 -- 皮肤名称，可以设置一个其他骨架数据名称来共享其皮肤数据。 （如果未设置，则使用默认的皮肤数据）
    self.textureAtlasName    = params.textureAtlasName or ""       -- 贴图集数据名称。 （如果未设置，将检索所有的贴图集数据）
    self.animName            = params.animName                     -- 初始骨骼动作名称（选填）
end

--------------------------
-- 渲染
--------------------------

function M:onRender()
    M.super.onRender(self)
    -- [本类调用]
    -- 加载骨骼数据
    self:addDragonBonesData()
    -- 创建骨架
    self:createArmature()
    -- 动作事件监听
    self:bindDBEvent(self.armatureDisplay)
end

-- 加载渲染以外的其他操作
function M:onEnterTransitionFinish()
    
end

-- 加载骨骼数据
function M:addDragonBonesData()
    if self.dragonBonesDataFile and self.dragonBonesTexFile then
	    dragonBones.CCFactory:loadDragonBonesData(self.dragonBonesDataFile, self.dragonBoneDataName)
        dragonBones.CCFactory:loadTextureAtlasData(self.dragonBonesTexFile, self.dragonBoneDataName)
    end
end

-- 创建骨骼
function M:createArmature()
    local armatureDisplay = dragonBones.CCFactory:buildArmatureDisplay(self.armatureName, self.dragonBonesName, self.skinName, self.textureAtlasName)
    CCNodeExtend.extend(armatureDisplay)
    -- 设置节点大小
    self:setContentSize(cc.size(armatureDisplay:cw(), armatureDisplay:ch()))
    armatureDisplay:anchor(cc.p(0.5, 0.5))
    local size = armatureDisplay:getContentSize()
    local anchor = armatureDisplay:getAnchorPoint()
    
    armatureDisplay:to(self):p(size.width * anchor.x, size.height * anchor.y)
    self.armatureDisplay = armatureDisplay
    -- 获取Animation
    self:getAnimation()
    if self.animName then
        self:play(self.animName)
    end
end



--------------------------
-- 功能函数
--------------------------
-- 获取armture
function M:getArmature()
    return self.armatureDisplay:getArmature()
end

-- 获取Animation
function M:getAnimation()
    self.animation = self.armatureDisplay:getAnimation()
    return self.animation
end

-- 动作播放
-- * param animationName         - 动画数据名称。 （如果未设置，则播放默认动画，或将暂停状态切换为播放状态，或重新播放之前播放的动画）
-- * param playTimes             - 【可选】循环播放次数。 [-1: 使用动画数据默认值, 0: 无限循环播放, [1~N]: 循环播放 N 次] （默认: -1）
-- * param setTimeScale          - 【可选】播放速度。[(-N~0): 倒转播放, 0: 停止播放, (0~1): 慢速播放, 1: 正常播放, (1~N): 快速播放]
-- * returns 播放的动画状态。
function M:play(animationName, playTimes, setTimeScale)
    setTimeScale = setTimeScale or 1
    local animation = self.animation
    if animation then
        animation = self:getAnimation()
    end
    playTimes = playTimes or -1
    local state = animation:play(animationName, playTimes)
    state:setTimeScale(setTimeScale)
    return state
end

-- 淡入播放指定的动画。
-- * param animationName - 动画数据名称。
-- * param fadeInTime - 淡入时间。 [-1: 使用动画数据默认值, [0~N]: 淡入时间 (以秒为单位)] （默认: -1）
-- * param playTimes - 播放次数。 [-1: 使用动画数据默认值, 0: 无限循环播放, [1~N]: 循环播放 N 次] （默认: -1）
-- * param params 其他可选参数
--[[
    {
        layer - 混合图层，图层高的动画状态会优先获取混合权重，当混合权重分配总和超过 1.0 时，剩余的动画状态将不能再获得权重分配。 （默认: 0）
        group - 混合组名称，该属性通常用来指定多个动画状态混合时的相互替换关系。 （默认: null）
        fadeOutMode - 淡出模式，该属性通常用来指定多个动画状态混合时的相互替换模式。 （默认: AnimationFadeOutMode.SameLayerAndGroup）
    }
]]
-- * returns 播放的动画状态。
function M:fadeInplay(animationName, fadeInTime, params)
    params = params or {}
    local playTimes   = params.playTimes or -1
    local layer       = params.layer or 0
    local group       = params.group or "" 
    local fadeOutMode = params.fadeOutMode or 0
    local state = self:getAnimation():fadeIn(animationName, fadeInTime, playTimes, layer, group, fadeOutMode)
    return state
end

-- 从指定时间开始播放指定的动画。
-- AnimationState* gotoAndPlayByTime(const std::string& animationName, float time = 0.f, int playTimes = -1);
-- * param animationName    - 动画数据名称。
-- * param time             - 播放开始的时间。 (以秒为单位)默认为0
-- * param playTimes        - 【可选】循环播放次数。 [-1: 使用动画数据默认值, 0: 无限循环播放, [1~N]: 循环播放 N 次] （默认: -1）
-- * returns 播放的动画状态。
function M:gotoAndPlayByTime(animationName, time, playTimes)
    time      = time or 0
    playTimes = playTimes or -1
    self:getAnimation():gotoAndPlayByTime(animationName, time, playTimes)
end

-- 在指定时间停止指定动画播放
-- AnimationState* gotoAndStopByTime(const std::string& animationName, float time = 0.f);
-- * param animationName    - 动画数据名称。
-- * param time             - [可选]停止的时间。 (以秒为单位)默认为0
-- * returns  播放的动画状态。
function M:gotoAndStopByTime(animationName, time)
    time      = time or 0
    self:getAnimation():gotoAndStopByTime(animationName, time)
end

-- 从指定帧开始播放指定的动画。
-- AnimationState* gotoAndPlayByFrame(const std::string& animationName, unsigned frame = 0, int playTimes = -1);
-- * param animationName    - 动画数据名称。
-- * param frame            - 播放开始的帧数。
-- * param playTimes        - [可选]播放次数。 [-1: 使用动画数据默认值, 0: 无限循环播放, [1~N]: 循环播放 N 次] （默认: -1）
-- * returns 播放的动画状态。
function M:gotoAndPlayByFrame(animationName, frame, playTimes)
    frame      = frame or 0
    playTimes = playTimes or -1
    self:getAnimation():gotoAndPlayByFrame(animationName, frame, playTimes)
end

--  在指定帧停止指定动画的播放
-- AnimationState* gotoAndStopByFrame(const std::string& animationName, unsigned frame = 0);
-- * param animationName       - 动画数据名称。
-- * param frame               - [可选]停止的帧数。默认0
-- * returns 播放的动画状态。
function M:gotoAndStopByFrame(animationName, frame)
    frame      = frame or 0
    self:getAnimation():gotoAndStopByFrame(animationName, frame)
end

-- 从指定进度开始播放指定的动画。
-- AnimationState* gotoAndPlayByProgress(const std::string& animationName, float progress = 0.f, int playTimes = -1);
-- * param animationName   - 动画数据名称。
-- * param progress        - 【可选】开始播放的进度（0 ~ 1）。
-- * param playTimes       - 【可选】播放次数。 [-1: 使用动画数据默认值, 0: 无限循环播放, [1~N]: 循环播放 N 次] （默认: -1）
-- * returns 播放的动画状态。
function M:gotoAndPlayByProgress(animationName, progress, playTimes)
    progress  = progress or 0
    playTimes = playTimes or -1
    self:getAnimation():gotoAndPlayByFrame(animationName, progress, playTimes)
end

-- 在指定的进度停止指定的动画播放。
-- AnimationState* gotoAndStopByProgress(const std::string& animationName, float progress = 0.f);
-- * param animationName   - 动画数据名称。
-- * param progress        - 停止进度。
-- * returns 播放的动画状态。
function M:gotoAndStopByProgress(animationName, progress)
    progress      = progress or 0
    self:getAnimation():gotoAndStopByProgress(animationName, progress)
end


-- 获取动作状态
function M:getAnimationState(animationName)
    local state = self:getAnimation():getState(animationName)
    return state
end

-- 获取指定的动画状态
-- * param animationName - 动画状态名称。
function M:getBone(boneName)
    local armature = self:getArmature():getBone(boneName)
    return armature
end


-- 常规换装
-- param slotName string  要换装的插槽名称
--[[
    1、typr(display) ~= "table" 
    ** params  display  要换的东西（可以是一个节点，骨骼、lable等等）   
    2、typr(display) == "table" 
    用特定的显示对象数据替换特定插槽当前的显示对象数据。
    用 "dragonBonesName/armatureName/slotName/displayName" 指定显示对象数据。
    ** param dragonBonesName  - DragonBonesData 实例的缓存名称。
    ** param armatureName     - 骨架数据名称。
    ** param slotName         - 插槽数据名称。
    ** param displayName      - 显示对象数据名称。
    ** param slot             - 插槽。
    ** param displayIndex     - [可选]被替换的显示对象数据的索引。 （如果未设置，则替换当前的显示对象数据）
    example
        local slot = self:getSlot("weapon");
        dragonBones.CCFactory:replaceSlotDisplay("dragonBonesName", "armatureName", "slotName", "displayName", slot);
]]
function M:changeSlotDisplay(slotName, display)
    local slot = self:getSlot(slotName)
    if type(display) == "table" then
        local displayIndex  = display.displayIndex or -1
        local dragonBonesName = display.dragonBonesName
        local armatureName    = display.armatureName
        local slotName        = display.slotName
        local displayName     = display.displayName
        dragonBones.CCFactory:replaceSlotDisplay(dragonBonesName, armatureName, slotName, displayName, slot, displayIndex)
    else
        slot:setDisplay(display)
    end
end

--  将特定的皮肤数据共享给特定的骨架使用。
--  param armature      - 骨架。
--  param skin          - 皮肤数据。
--  param isOverride    - [可选]是否完全覆盖原来的皮肤。 （默认: false）
--  param exclude       - [可选]不需要被替换的插槽名称列表。
--[[
    example
        local armatureA = dragonBones.CCFactory:buildArmature("armatureA", "dragonBonesA")
        local armatureDataB = dragonBones.CCFactory:getArmatureData("armatureB", "dragonBonesB")
        if (armatureDataB and armatureDataB.defaultSkin) then
            dragonBones.CCFactory:replaceSkin(armatureA, armatureDataB:getDefaultSkin(), false)
        end
]]
function M:replaceSkin(armature, skin, isOverride, exclude)
    isOverride = isOverride or false
    dragonBones.CCFactory:replaceSkin(armature, skin, isOverride, exclude)
end












----------------------------------------------------
-- 骨骼事件绑定
----------------------------------------------------
-- 骨骼事件绑定
function M:bindDBEvent(armatureDisplay)
    armatureDisplay:addDBEventListener("start", handler(self, self.animationEventHandler))

    armatureDisplay:addDBEventListener("loopComplete", handler(self, self.animationEventHandler))

    armatureDisplay:addDBEventListener("complete", handler(self, self.animationEventHandler))

    armatureDisplay:addDBEventListener("fadeIn", handler(self, self.animationEventHandler))

    armatureDisplay:addDBEventListener("fadeInComplete", handler(self, self.animationEventHandler))

    armatureDisplay:addDBEventListener("fadeOut", handler(self, self.animationEventHandler))
 
    armatureDisplay:addDBEventListener("fadeOutComplete", handler(self, self.animationEventHandler))

    armatureDisplay:addDBEventListener("frameEvent", handler(self, self.animationEventHandler))

    armatureDisplay:addDBEventListener("soundEvent", handler(self, self.animationEventHandler))
end

-- 注销骨骼动画事件
function M:removeDBEventListener(armatureDisplay)    
    armatureDisplay:removeDBEventListener("start")
    armatureDisplay:removeDBEventListener("loopComplete")
    armatureDisplay:removeDBEventListener("complete")
    armatureDisplay:removeDBEventListener("fadeIn")
    armatureDisplay:removeDBEventListener("fadeInComplete")
    armatureDisplay:removeDBEventListener("fadeOut")
    armatureDisplay:removeDBEventListener("fadeOutComplete")
    armatureDisplay:removeDBEventListener("frameEvent")
    armatureDisplay:removeDBEventListener("soundEvent")
end




--------------------------
-- 父类重写
--------------------------
-- 事件回调
--[[
    其中enventObject包含的数据有：
    格式说明: 参数类型  参数名称  注释
    std::string type 事件类型。
    float time;  如果是帧事件，此值用来描述该事件在动画时间轴中所处的时间。（以秒为单位）
    std::string name; 事件名称。 (帧事件的名称或帧声音的名称)
    Armature armature; 发出该事件的骨架。
    Bone bone; 发出该事件的骨骼。
    Slot slot; 发出该事件的插槽。
    AnimationState animationState; 发出该事件的动画状态。
    UserData data;  自定义数据。
    注意：其中time，只有在帧事件和声音事件的时候存在。time只有帧事件的时候才存在。
]]
function M:animationEventHandler(eventObject)
    if eventObject.type == "start" then

    elseif eventObject.type == "loopComplete" then

    elseif eventObject.type == "complete" then

    elseif eventObject.type == "fadeIn" then       

    elseif eventObject.type == "fadeInComplete" then

    elseif eventObject.type == "fadeOut" then

    elseif eventObject.type == "fadeOutComplete" then

    elseif eventObject.type == "frameEvent" then
 
    elseif eventObject.type == "soundEvent" then

    end
end




--------------------------
-- 属性
--------------------------







----------------------------------------------------
-- 析构
--------------------------

function M:onDestructor()
    -- [超类调用]
    M.super.onDestructor(self)
    -- [本类调用]
    self:removeDBEventListener(self.armatureDisplay)   
end








return M






